package net.qiqb.spring;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ClassLoaderUtil;
import net.qiqb.core.build.AggregateRootDefineBuilder;
import net.qiqb.core.build.QiqbBuilder;
import net.qiqb.core.domain.annotation.AggregateLoader;
import net.qiqb.core.domain.definition.AggregateRootDefine;
import net.qiqb.core.domain.event.DomainEventPersistence;
import net.qiqb.core.domain.event.sender.DomainEventSender;
import net.qiqb.core.domain.log.AggregateChangesLogger;
import net.qiqb.core.domain.persist.annotation.Transaction;

import net.qiqb.core.executing.annotation.AggregateObjectPostProcessor;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ScannedGenericBeanDefinition;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class SpringExecutionContext {


    private final Set<BeanDefinition> commandBeanDefinition = new HashSet<>();

    private final Set<BeanDefinition> aggregateRootBeanDefinition = new HashSet<>();

    private Set<BeanDefinition> attachAggregateBeanDefinition = new HashSet<>();


    private final QiqbBuilder qiqbBuilder = new QiqbBuilder();

    public void initExecutionContext(ApplicationContext applicationContext) {
        final Map<String, Object> aggregateLoaders = applicationContext.getBeansWithAnnotation(AggregateLoader.class);
        final AggregatePersistenceManager aggregatePersistenceManager = applicationContext.getBean(AggregatePersistenceManager.class);
        // 解析聚合根对象
        for (BeanDefinition beanDefinition : aggregateRootBeanDefinition) {
            if (beanDefinition instanceof ScannedGenericBeanDefinition scannedGenericBeanDefinition) {
                final String beanClassName = beanDefinition.getBeanClassName();
                if (beanClassName == null) {
                    continue;
                }

                // registerDomainDefinition(new AggregateRootConfig(domainName, beanClassName));
                Class<?> aggregateRootClass = ClassLoaderUtil.loadClass(beanClassName);

                final AggregateRootDefineBuilder aggregateRootDefineBuilder = new AggregateRootDefineBuilder(aggregateRootClass);
                final AggregateRootDefine aggregateRootDefine = aggregateRootDefineBuilder
                        // 设置加载器
                        .addAllAggregateLoader(aggregateLoaders.values())
                        .setAggregatePersistence(aggregatePersistenceManager.getAggregatePersistence(aggregateRootDefineBuilder.getName()))
                        .setExtendedAggregatePersistence(aggregatePersistenceManager.getExtendedAggregatePersistence(aggregateRootDefineBuilder.getName()))
                        .build();
                qiqbBuilder.registerEntityDefine(aggregateRootDefine);
            }

        }

        qiqbBuilder.registerTransaction(applicationContext.getBean(Transaction.class))
                .registerDomainEventPersistence(applicationContext.getBean(DomainEventPersistence.class))
                .registerAggregateChangesLogger(applicationContext.getBean(AggregateChangesLogger.class))
                .registerDomainEventSender(applicationContext.getBean(DomainEventSender.class))
                .addObtainAggregateObjectPostProcessor(applicationContext.getBeansOfType(AggregateObjectPostProcessor.class).values())
                .build()
        ;
        /*for (BeanDefinition beanDefinition : attachAggregateBeanDefinition) {
            if (beanDefinition instanceof ScannedGenericBeanDefinition scannedGenericBeanDefinition) {
                String domainName = beanDefinition.getBeanClassName();
                final MergedAnnotation<AttachedAggregate> attachAggregateAnnotation = scannedGenericBeanDefinition.getMetadata().getAnnotations().get(AttachedAggregate.class);
                // 聚合根类
                final Optional<Object> attachAggregateAnnotationValue = attachAggregateAnnotation.getValue("value");
                if (attachAggregateAnnotationValue.isEmpty()) {
                    throw new IllegalStateException("找不到对应聚合根");
                }
                Class<?> aggregateRootClass = (Class<?>) attachAggregateAnnotationValue.get();
                final Optional<Object> nameAttr = attachAggregateAnnotation.getValue("name");

                if (nameAttr.isPresent()) {
                    final String nameStr = nameAttr.get().toString();
                    if (StrUtil.isNotEmpty(nameStr)) {
                        domainName = nameStr;
                    }
                }
                final AggregateRootConfig aggregateRootConfig = (AggregateRootConfig) getDomainConfigRegistrar().getDomainDefinition(aggregateRootClass.getName());
                registerDomainDefinition(new AttachAggregateConfig(domainName, beanDefinition.getBeanClassName(), aggregateRootConfig));
            }
        }*/

        /*for (BeanDefinition beanDefinition : commandBeanDefinition) {
            if (beanDefinition instanceof ScannedGenericBeanDefinition scannedGenericBeanDefinition) {
                String commandName = beanDefinition.getBeanClassName();

                final MergedAnnotation<Command> commandMergedAnnotation = scannedGenericBeanDefinition.getMetadata().getAnnotations().get(Command.class);
                final Optional<Object> nameAttr = commandMergedAnnotation.getValue("name");
                final Optional<Object> valueAttr = commandMergedAnnotation.getValue("value");
                // 默认是操作的类定义
                String domainName = "";
                if (valueAttr.isPresent()) {
                    final Class<?> domainClass = (Class<?>) valueAttr.get();
                    domainName = domainClass.getName();
                }
                final Optional<Object> domainNameAttr = commandMergedAnnotation.getValue("domainName");
                if (nameAttr.isPresent()) {
                    final String nameStr = nameAttr.get().toString();
                    if (StrUtil.isNotEmpty(nameStr)) {
                        commandName = nameStr;
                    }
                }
                if (domainNameAttr.isPresent()) {
                    final String domainNameStr = domainNameAttr.get().toString();
                    if (StrUtil.isNotEmpty(domainNameStr)) {
                        domainName = domainNameStr;
                    }
                }
                final CommandConfig commandDefinition = new CommandConfig(commandName, beanDefinition.getBeanClassName(), domainName);
                commandDefinition.setDomainConfig(getDomainConfigRegistrar().getDomainDefinition(domainName));
                registerCommandDefinition(commandDefinition);
            }

        }*/
    }


    public void addAllCommandBeanDefinition(Set<BeanDefinition> commandBeanDefinition) {
        this.commandBeanDefinition.addAll(commandBeanDefinition);
    }

    public void addAllAggregateRootBeanDefinition(Set<BeanDefinition> aggregateRootBeanDefinition) {
        this.aggregateRootBeanDefinition.addAll(aggregateRootBeanDefinition);
    }

    public void addAllAttachAggregateBeanDefinition(Set<BeanDefinition> attachAggregateBeanDefinition) {
        this.attachAggregateBeanDefinition.addAll(attachAggregateBeanDefinition);
    }

    public QiqbBuilder getQiqbBuilder() {
        Assert.notNull(qiqbBuilder);
        return this.qiqbBuilder;
    }

}
